/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
** 
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
** 
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
** 
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockManager.cpp
/// \author Uwe Kindler
/// \date   26.02.2017
/// \brief  Implementation of CDockManager class
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <AutoHideDockContainer.h>
#include "DockWidgetTab.h"
#include "DockManager.h"

#include <algorithm>
#include <iostream>

#include <QMainWindow>
#include <QList>
#include <QMap>
#include <QVariant>
#include <QDebug>
#include <QFile>
#include <QAction>
#include <QXmlStreamWriter>
#include <QSettings>
#include <QMenu>
#include <QApplication>
#include <QWindow>
#include <QWindowStateChangeEvent>

#include "FloatingDockContainer.h"
#include "DockOverlay.h"
#include "DockWidget.h"
#include "ads_globals.h"
#include "DockAreaWidget.h"
#include "IconProvider.h"
#include "DockingStateReader.h"
#include "DockAreaTitleBar.h"
#include "DockFocusController.h"
#include "DockSplitter.h"

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include "linux/FloatingWidgetTitleBar.h"
#endif

/**
 * 初始化由.qrc文件指定的资源和指定的基本名称。
 * 通常，在应用程序构建时，资源会自动在启动时加载。
 * Q_INIT_RESOURCE() 宏在某些平台上对于存储在静态库中的资源是必需的。
 * 因为如果将 Q_INIT_RESOURCE 放入 loadStyleSheet() 函数中，GCC 会导致链接错误，
 * 所以我们将其放入 ads 命名空间之外的一个函数中。
 */
/**
 * 初始化资源
 */
static void initResource()
{
    Q_INIT_RESOURCE(ads);
}

namespace ads
{
    /**
     * 内部文件版本，以防结构在内部发生变化
     */
    enum eStateFileVersion
    {
        InitialVersion = 0,      //!< 初始版本
        Version1 = 1,            //!< 版本1
        CurrentVersion = Version1//!< 当前版本
    };

    // 默认的配置标志为 DefaultNonOpaqueConfig
    static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig;
    // 默认情况下，自动隐藏功能被禁用
    static CDockManager::AutoHideFlags StaticAutoHideConfigFlags;
    // 浮动容器的标题
    static QString FloatingContainersTitle;

    /**
     * CDockManager 类的私有数据类（pimpl）
     */
    struct DockManagerPrivate
    {
        CDockManager* _this;
        QList<CFloatingDockContainer*> FloatingWidgets; // 浮动窗口小部件列表
        QList<CFloatingDockContainer*> HiddenFloatingWidgets; // 隐藏的浮动窗口小部件列表
        QList<CDockContainerWidget*> Containers; // 容器列表
        CDockOverlay* ContainerOverlay; // 容器叠加层
        CDockOverlay* DockAreaOverlay; // Dock 区域叠加层
        QMap<QString, CDockWidget*> DockWidgetsMap; // Dock 小部件映射
        QMap<QString, QByteArray> Perspectives; // 透视图映射
        QMap<QString, QMenu*> ViewMenuGroups; // 视图菜单组映射
        QMenu* ViewMenu; // 视图菜单
        CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted; // 视图菜单插入顺序，默认按字母顺序排序
        bool RestoringState = false; // 是否正在恢复状态
        QVector<CFloatingDockContainer*> UninitializedFloatingWidgets; // 未初始化的浮动窗口小部件列表
        CDockFocusController* FocusController = nullptr; // 焦点控制器
        CDockWidget* CentralWidget = nullptr; // 中心小部件
        bool IsLeavingMinimized = false; // 是否正在离开最小化状态

        /**
         * 私有数据构造函数
         */
        DockManagerPrivate(CDockManager* _public);

        /**
         * 检查给定的数据流是否是有效的停靠系统状态文件。
         */
        bool checkFormat(const QByteArray& state, int version);

        /**
         * 从 XML 中恢复状态
         */
        bool restoreStateFromXml(const QByteArray& state, int version, bool Testing = internal::Restore);

        /**
         * 恢复状态
         */
        bool restoreState(const QByteArray& state, int version);

        /**
         * 恢复 Dock 小部件的打开状态
         */
        void restoreDockWidgetsOpenState();

        /**
         * 恢复 Dock 区域的索引
         */
        void restoreDockAreasIndices();

        /**
         * 发出顶层事件
         */
        void emitTopLevelEvents();

        /**
         * 隐藏浮动窗口小部件
         */
        void hideFloatingWidgets();

        /**
         * 标记 Dock 小部件为脏
         */
        void markDockWidgetsDirty();

        /**
         * 恢复具有给定索引的容器
         */
        bool restoreContainer(int Index, CDockingStateReader& stream, bool Testing);

        /**
         * 加载样式表
         */
        void loadStylesheet();

        /**
         * 将动作添加到菜单中（可选择按排序顺序插入）
         */
        void addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted);
    };

    // DockManagerPrivate 结构体
    //============================================================================

    DockManagerPrivate::DockManagerPrivate(CDockManager* _public) :
            _this(_public)
    {
    }

    //============================================================================

    void DockManagerPrivate::loadStylesheet()
    {
        initResource();
        QString Result;
        QString FileName = ":ads/stylesheets/";
        FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) ? "focus_highlighting" : "default";
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
        FileName += "_linux";
#endif
        FileName += ".css";
        QFile StyleSheetFile(FileName);
        StyleSheetFile.open(QIODevice::ReadOnly);
        QTextStream StyleSheetStream(&StyleSheetFile);
        Result = StyleSheetStream.readAll();
        StyleSheetFile.close();
        _this->setStyleSheet(Result);
    }

    //============================================================================

    bool DockManagerPrivate::restoreContainer(int Index, CDockingStateReader& stream, bool Testing)
    {
        if (Testing)
        {
            Index = 0;
        }

        bool Result = false;

        if (Index >= Containers.count())
        {
            CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
            Result = FloatingWidget->restoreState(stream, Testing);
        }
        else
        {
            auto Container = Containers[Index];

            if (Container->isFloating())
            {
                Result = Container->floatingWidget()->restoreState(stream, Testing);
            }
            else
            {
                Result = Container->restoreState(stream, Testing);
            }
        }

        return Result;
    }

    //============================================================================

    bool DockManagerPrivate::checkFormat(const QByteArray& state, int version)
    {
        return restoreStateFromXml(state, version, internal::RestoreTesting);
    }

    //============================================================================

    bool DockManagerPrivate::restoreStateFromXml(const QByteArray& state, int version, bool Testing)
    {
        Q_UNUSED(version);

        if (state.isEmpty())
        {
            return false;
        }

        CDockingStateReader s(state);
        s.readNextStartElement();

        if (s.name() != QLatin1String("QtAdvancedDockingSystem"))
        {
            return false;
        }

        bool ok;
        int v = s.attributes().value("Version").toInt(&ok);

        if (!ok || v > CurrentVersion)
        {
            return false;
        }

        s.setFileVersion(v);

        // 旧文件不支持 UserVersion，但我们仍然希望加载它们，因此我们首先测试属性是否存在
        if (!s.attributes().value("UserVersion").isEmpty())
        {
            v = s.attributes().value("UserVersion").toInt(&ok);

            if (!ok || v != version)
            {
                return false;
            }
        }

        bool Result = true;

#ifdef ADS_DEBUG_PRINT
        int DockContainers = s.attributes().value("Containers").toInt();
#endif

        if (CentralWidget)
        {
            const auto CentralWidgetAttribute = s.attributes().value("CentralWidget");

            // 如果我们有一个中心小部件，但状态中没有中心小部件，那么就有问题。
            if (CentralWidgetAttribute.isEmpty())
            {
                qWarning() << "Dock manager has central widget but saved state does not have central widget.";
                return false;
            }

            // 如果中心小部件的对象名称与保存的中心小部件的名称不匹配，则有问题。
            if (CentralWidget->objectName() != CentralWidgetAttribute.toString())
            {
                qWarning() << "Object name of central widget does not match name of central widget in saved state.";
                return false;
            }
        }

        int DockContainerCount = 0;

        while (s.readNextStartElement())
        {
            if (s.name() == QLatin1String("Container"))
            {
                Result = restoreContainer(DockContainerCount, s, Testing);

                if (!Result)
                {
                    break;
                }

                DockContainerCount++;
            }
        }

        if (!Testing)
        {
            // 删除剩余的空浮动窗口小部件
            int FloatingWidgetIndex = DockContainerCount - 1;

            for (int i = FloatingWidgetIndex; i < FloatingWidgets.count(); ++i)
            {
                auto* floatingWidget = FloatingWidgets[i];
                _this->removeDockContainer(floatingWidget->dockContainer());
                floatingWidget->deleteLater();
            }
        }

        return Result;
    }
}


//============================================================================
// 恢复所有未处理的停靠窗口的打开状态
void DockManagerPrivate::restoreDockWidgetsOpenState()
{
    // 所有未处理的停靠窗口对用户不可见，没有分配的停靠区域
    // 它们不属于任何停靠容器，直到用户下次切换视图操作
    for (auto DockWidget : DockWidgetsMap)
    {
        if (DockWidget->property(internal::DirtyProperty).toBool())
        {
            // 如果DockWidget是一个未分配的自动隐藏窗口，
            // 则需要删除自动隐藏容器
            if (DockWidget->isAutoHide())
            {
                DockWidget->autoHideDockContainer()->cleanupAndDelete();
            }
            DockWidget->flagAsUnassigned();
            Q_EMIT DockWidget->viewToggled(false);
        }
        else
        {
            DockWidget->toggleViewInternal(!DockWidget->property(internal::ClosedProperty).toBool());
        }
    }
}

//============================================================================
// 恢复停靠区域的索引
void DockManagerPrivate::restoreDockAreasIndices()
{
    // 现在所有的停靠区域都已经恢复，我们设置停靠区域的索引
    // 因为之前的toggleView()操作已经改变了停靠区域的索引
    int count = 0;
    for (auto DockContainer : Containers)
    {
        count++;
        for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
        {
            CDockAreaWidget* DockArea = DockContainer->dockArea(i);
            QString DockWidgetName = DockArea->property("currentDockWidget").toString();
            CDockWidget* DockWidget = nullptr;
            if (!DockWidgetName.isEmpty())
            {
                DockWidget = _this->findDockWidget(DockWidgetName);
            }
            if (!DockWidget || DockWidget->isClosed())
            {
                int index = DockArea->indexOfFirstOpenDockWidget();
                if (index < 0)
                {
                    continue;
                }
                DockArea->setCurrentIndex(index);
            }
            else
            {
                DockArea->internalSetCurrentDockWidget(DockWidget);
            }
        }
    }
}

//============================================================================
// 发送topLevelChanged()信号给所有的停靠窗口
void DockManagerPrivate::emitTopLevelEvents()
{
    // 最后，我们需要为所有的停靠窗口发送topLevelChanged()信号
    for (auto DockContainer : Containers)
    {
        CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget();
        if (TopLevelDockWidget)
        {
            TopLevelDockWidget->emitTopLevelChanged(true);
        }
        else
        {
            for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
            {
                auto DockArea = DockContainer->dockArea(i);
                for (auto DockWidget : DockArea->dockWidgets())
                {
                    DockWidget->emitTopLevelChanged(false);
                }
            }
        }
    }
}

//============================================================================
// 恢复状态
bool DockManagerPrivate::restoreState(const QByteArray& state, int version)
{
    QByteArray compressedState = state.startsWith("<?xml") ? state : qUncompress(state);
    if (!checkFormat(compressedState, version))
    {
        ADS_PRINT("checkFormat: Error checking format!!!!!!!");
        return false;
    }
    // 隐藏浮动窗口的更新
    hideFloatingWidgets();
    markDockWidgetsDirty();
    if (!restoreStateFromXml(compressedState, version))
    {
        ADS_PRINT("restoreState: Error restoring state!!!!!!!");
        return false;
    }
    restoreDockWidgetsOpenState();
    restoreDockAreasIndices();
    emitTopLevelEvents();
    _this->dumpLayout();
    return true;
}

//============================================================================
// 将动作添加到菜单中
void DockManagerPrivate::addActionToMenu(QAction* action, QMenu* menu, bool insertSorted)
{
    if (insertSorted)
    {
        auto actions = menu->actions();
        auto it = std::find_if(actions.begin(), actions.end(),
                               [&action](const QAction* a)
                               {
                                   return a->text().compare(action->text(), Qt::CaseInsensitive) > 0;
                               });
        if (it == actions.end())
        {
            menu->addAction(action);
        }
        else
        {
            menu->insertAction(*it, action);
        }
    }
    else
    {
        menu->addAction(action);
    }
}

//============================================================================
CDockManager::CDockManager(QWidget *parent) :
        CDockContainerWidget(this, parent),
        d(new DockManagerPrivate(this))
{
    createRootSplitter();
    createSideTabBarWidgets();
    QMainWindow* mainWindow = qobject_cast<QMainWindow*>(parent);
    if (mainWindow)
    {
        mainWindow->setCentralWidget(this);
    }
    d->ViewMenu = new QMenu(tr("Show View"), this);
    d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
    d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
    d->Containers.append(this);
    d->loadStylesheet();
    if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
    {
        d->FocusController = new CDockFocusController(this);
    }
    window()->installEventFilter(this);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    connect(qApp, &QApplication::focusWindowChanged, [](QWindow* focusWindow)
    {
        // 将模态对话框置于前景，以确保它们在任何浮动停靠窗口之前
        if (focusWindow && focusWindow->isModal())
        {
            focusWindow->raise();
        }
    });
#endif
}

//============================================================================
CDockManager::~CDockManager()
{
    // 修复内存泄漏，参见 https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/307
    std::vector<ads::CDockAreaWidget*> areas;
    for (int i = 0; i != dockAreaCount(); ++i)
    {
        areas.push_back(dockArea(i));
    }
    for (auto area : areas)
    {
        for (auto widget : area->dockWidgets())
            delete widget;
        delete area;
    }
    auto FloatingWidgets = d->FloatingWidgets;
    for (auto FloatingWidget : FloatingWidgets)
    {
        delete FloatingWidget;
    }
    delete d;
}
//============================================================================
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
bool CDockManager::eventFilter(QObject *obj, QEvent *e)
{
    // 模拟 Qt:Tool 的行为。
    // 这是因为在某些窗口管理器上，工具窗口无法最大化。
    // 窗口始终在主窗口之上。
    if (e->type() == QEvent::WindowActivate)
    {
        for (auto _window : floatingWidgets())
        {
            if (!_window->isVisible() || window()->isMinimized())
            {
                continue;
            }
            // setWindowFlags(Qt::WindowStaysOnTopHint) 会隐藏窗口，因此需要调用 show。
            // 这会导致闪烁和一个可怕的无限循环（在 Ubuntu 上也会出现错误行为）。
            // 所以我们自己处理。
            if (QGuiApplication::platformName() == QLatin1String("xcb"))
            {
                internal::xcb_update_prop(true, _window->window()->winId(),
                    "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
            }
            else
            {
                _window->setWindowFlag(Qt::WindowStaysOnTopHint, true);
            }
        }
    }
    else if (e->type() == QEvent::WindowDeactivate)
    {
        for (auto _window : floatingWidgets())
        {
            if (!_window->isVisible() || window()->isMinimized())
            {
                continue;
            }
            if (QGuiApplication::platformName() == QLatin1String("xcb"))
            {
                internal::xcb_update_prop(false, _window->window()->winId(),
                    "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
            }
            else
            {
                _window->setWindowFlag(Qt::WindowStaysOnTopHint, false);
            }
            _window->raise();
        }
    }
    // 与 MainWindow 同步最小化
    if (e->type() == QEvent::WindowStateChange)
    {
        for (auto _window : floatingWidgets())
        {
            if (!_window->isVisible())
            {
                continue;
            }
            if (window()->isMinimized())
            {
                _window->showMinimized();
            }
            else
            {
                _window->setWindowState(_window->windowState() & (~Qt::WindowMinimized));
            }
        }
        if (!window()->isMinimized())
        {
            QApplication::setActiveWindow(window());
        }
    }
    return Super::eventFilter(obj, e);
}
#else
//============================================================================
// CDockManager类的事件过滤器
bool CDockManager::eventFilter(QObject *obj, QEvent *e)
{
    // 如果事件类型是窗口状态改变
    if (e->type() == QEvent::WindowStateChange)
    {
        // 将事件转换为QWindowStateChangeEvent类型
        QWindowStateChangeEvent* ev = static_cast<QWindowStateChangeEvent*>(e);
        // 如果旧状态是最小化
        if (ev->oldState().testFlag(Qt::WindowMinimized))
        {
            // 设置正在离开最小化状态为true
            d->IsLeavingMinimized = true;
            // 通过Qt的信号槽机制，在下一个事件循环中调用endLeavingMinimizedState()方法
            QMetaObject::invokeMethod(this, "endLeavingMinimizedState", Qt::QueuedConnection);
        }
    }
    // 调用父类的事件过滤器
    return Super::eventFilter(obj, e);
}
#endif
//============================================================================
// 结束离开最小化状态
void CDockManager::endLeavingMinimizedState()
{
    // 设置正在离开最小化状态为false
    d->IsLeavingMinimized = false;
    // 激活窗口
    this->activateWindow();
}
//============================================================================
// 是否正在离开最小化状态
bool CDockManager::isLeavingMinimizedState() const
{
    return d->IsLeavingMinimized;
}
//============================================================================
// 注册浮动窗口
void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget)
{
    // 将浮动窗口添加到列表中
    d->FloatingWidgets.append(FloatingWidget);
    // 发射信号，通知浮动窗口已创建
    Q_EMIT floatingWidgetCreated(FloatingWidget);
    // 打印浮动窗口数量
    ADS_PRINT("d->FloatingWidgets.count() " << d->FloatingWidgets.count());
}
//============================================================================
// 移除浮动窗口
void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
{
    // 从列表中移除浮动窗口
    d->FloatingWidgets.removeAll(FloatingWidget);
}
//============================================================================
// 注册停靠容器
void CDockManager::registerDockContainer(CDockContainerWidget* DockContainer)
{
    // 将停靠容器添加到列表中
    d->Containers.append(DockContainer);
}
//============================================================================
// 移除停靠容器
void CDockManager::removeDockContainer(CDockContainerWidget* DockContainer)
{
    // 如果不是当前对象
    if (this != DockContainer)
    {
        // 从列表中移除停靠容器
        d->Containers.removeAll(DockContainer);
    }
}
//============================================================================
// 获取容器覆盖物
CDockOverlay* CDockManager::containerOverlay() const
{
    return d->ContainerOverlay;
}
//============================================================================
// 获取停靠区域覆盖物
CDockOverlay* CDockManager::dockAreaOverlay() const
{
    return d->DockAreaOverlay;
}
//============================================================================
// 获取所有停靠容器
const QList<CDockContainerWidget*> CDockManager::dockContainers() const
{
    return d->Containers;
}
//============================================================================
// 获取所有浮动窗口
const QList<CFloatingDockContainer*> CDockManager::floatingWidgets() const
{
    return d->FloatingWidgets;
}
//============================================================================
// 获取Z轴顺序索引
unsigned int CDockManager::zOrderIndex() const
{
    return 0;
}
//============================================================================
// 保存状态
QByteArray CDockManager::saveState(int version) const
{
    // 创建XML数据流
    QByteArray xmldata;
    QXmlStreamWriter s(&xmldata);
    auto ConfigFlags = CDockManager::configFlags();
    // 设置是否自动格式化XML
    s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled));
    s.writeStartDocument();
    s.writeStartElement("QtAdvancedDockingSystem");
    s.writeAttribute("Version", QString::number(CurrentVersion));
    s.writeAttribute("UserVersion", QString::number(version));
    s.writeAttribute("Containers", QString::number(d->Containers.count()));
    if (d->CentralWidget)
    {
        s.writeAttribute("CentralWidget", d->CentralWidget->objectName());
    }
    for (auto Container : d->Containers)
    {
        Container->saveState(s);
    }
    s.writeEndElement();
    s.writeEndDocument();
    // 如果启用了XML压缩
    return ConfigFlags.testFlag(XmlCompressionEnabled) ? qCompress(xmldata, 9) : xmldata;
}

// 重构后的代码如下：
//============================================================================

// 恢复状态
bool CDockManager::restoreState(const QByteArray &state, int version)
{
    // 防止多次调用，只要状态未恢复即可。这可能发生在某个地方调用了QApplication::processEvents()
    if (d->RestoringState)
    {
        return false;
    }

    // 在这里隐藏整个停靠管理器。恢复状态意味着从停靠区域内部堆栈布局中删除DockWidgets，
    // 这意味着每次删除小部件时，堆栈将显示并提升到下一个可用小部件，这将触发停靠小部件的显示事件。
    // 为了避免这种情况，我们隐藏停靠管理器。因为在完成此函数之前不会处理应用程序事件，所以用户看不到这个隐藏。
    bool IsHidden = this->isHidden();
    if (!IsHidden)
    {
        hide();
    }

    d->RestoringState = true;
    Q_EMIT restoringState();
    bool Result = d->restoreState(state, version);
    d->RestoringState = false;

    if (!IsHidden)
    {
        show();
    }

    Q_EMIT stateRestored();
    return Result;
}

// 添加浮动停靠小部件
CFloatingDockContainer* CDockManager::addDockWidgetFloating(CDockWidget* Dockwidget)
{
    d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);

    CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget();
    if (OldDockArea)
    {
        OldDockArea->removeDockWidget(Dockwidget);
    }

    Dockwidget->setDockManager(this);

    CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(Dockwidget);
    FloatingWidget->resize(Dockwidget->size());

    if (isVisible())
    {
        FloatingWidget->show();
    }
    else
    {
        d->UninitializedFloatingWidgets.append(FloatingWidget);
    }

    Q_EMIT dockWidgetAdded(Dockwidget);
    return FloatingWidget;
}

// 显示事件
void CDockManager::showEvent(QShowEvent *event)
{
    Super::showEvent(event);

    // 修复问题＃380
    restoreHiddenFloatingWidgets();

    if (d->UninitializedFloatingWidgets.empty())
    {
        return;
    }

    for (auto FloatingWidget : d->UninitializedFloatingWidgets)
    {
        // 检查是否有人在显示停靠管理器之前关闭了浮动停靠小部件
        if (FloatingWidget->dockContainer()->hasOpenDockAreas())
        {
            FloatingWidget->show();
        }
    }

    d->UninitializedFloatingWidgets.clear();
}

// 恢复隐藏的浮动停靠小部件
void CDockManager::restoreHiddenFloatingWidgets()
{
    if (d->HiddenFloatingWidgets.isEmpty())
    {
        return;
    }

    // 恢复隐藏的浮动小部件，这些小部件在hideManagerAndFloatingWidgets时被隐藏
    for (auto FloatingWidget : d->HiddenFloatingWidgets)
    {
        bool hasDockWidgetVisible = false;

        // 防止CFloatingDockContainer显示为空
        // 如果在其他情况下CFloatingDockContainer显示为空，可以将此代码移到CFloatingDockContainer::showEvent(QShowEvent *event)中
        // 但为了确保修复问题＃380的更改不会影响现有行为，暂时将其保留在这里
        for (auto dockWidget : FloatingWidget->dockWidgets())
        {
            if (dockWidget->toggleViewAction()->isChecked())
            {
                dockWidget->toggleView(true);
                hasDockWidgetVisible = true;
            }
        }

        if (hasDockWidgetVisible)
        {
            FloatingWidget->show();
        }
    }

    d->HiddenFloatingWidgets.clear();
}

// 添加停靠小部件
CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget, int Index)
{
    d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);

    auto Container = DockAreaWidget ? DockAreaWidget->dockContainer() : this;
    auto AreaOfAddedDockWidget = Container->addDockWidget(area, Dockwidget, DockAreaWidget, Index);

    Q_EMIT dockWidgetAdded(Dockwidget);
    return AreaOfAddedDockWidget;
}

// 添加停靠小部件到容器
CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget)
{
    d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);

    auto AreaOfAddedDockWidget = DockContainerWidget->addDockWidget(area, Dockwidget);

    Q_EMIT dockWidgetAdded(Dockwidget);
    return AreaOfAddedDockWidget;
}

// 添加自动隐藏停靠小部件
CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget)
{
    return addAutoHideDockWidgetToContainer(area, Dockwidget, this);
}

// 添加自动隐藏停靠小部件到容器
CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(SideBarLocation area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget)
{
    d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);

    auto container = DockContainerWidget->createAndSetupAutoHideContainer(area, Dockwidget);
    container->collapseView(true);

    Q_EMIT dockWidgetAdded(Dockwidget);
    return container;
}

//============================================================================
// 添加一个DockWidget到指定的区域，并将其作为一个选项卡添加到已有的区域中
CDockAreaWidget* CDockManager::addDockWidgetTab(DockWidgetArea area,
                                                CDockWidget* dockWidget)
{
    // 获取最后一个添加的区域
    CDockAreaWidget* areaWidget = lastAddedDockAreaWidget(area);
    if (areaWidget)
    {
        // 将dockWidget作为选项卡添加到区域中心区域
        return addDockWidget(ads::CenterDockWidgetArea, dockWidget, areaWidget);
    }
    else
    {
        // 将dockWidget添加到指定区域
        return addDockWidget(area, dockWidget, nullptr);
    }
}
//============================================================================
// 将一个DockWidget作为选项卡添加到指定的区域中
CDockAreaWidget* CDockManager::addDockWidgetTabToArea(CDockWidget* dockWidget,
                                                      CDockAreaWidget* dockAreaWidget, int index)
{
    return addDockWidget(ads::CenterDockWidgetArea, dockWidget, dockAreaWidget, index);
}
//============================================================================
// 根据ObjectName查找DockWidget
CDockWidget* CDockManager::findDockWidget(const QString& objectName) const
{
    return d->DockWidgetsMap.value(objectName, nullptr);
}
//============================================================================
// 移除一个DockWidget
void CDockManager::removeDockWidget(CDockWidget* dockWidget)
{
    // 发送dockWidget即将被移除的信号
    Q_EMIT dockWidgetAboutToBeRemoved(dockWidget);
    // 从DockWidgetsMap中移除dockWidget
    d->DockWidgetsMap.remove(dockWidget->objectName());
    // 调用基类的removeDockWidget方法移除dockWidget
    CDockContainerWidget::removeDockWidget(dockWidget);
    // 设置dockWidget的dockManager为nullptr
    dockWidget->setDockManager(nullptr);
    // 发送dockWidget已被移除的信号
    Q_EMIT dockWidgetRemoved(dockWidget);
}
//============================================================================
// 获取DockWidgetsMap
QMap<QString, CDockWidget*> CDockManager::dockWidgetsMap() const
{
    return d->DockWidgetsMap;
}
//============================================================================
// 添加一个透视图
void CDockManager::addPerspective(const QString& uniquePerspectiveName)
{
    // 将当前状态保存到Perspectives中
    d->Perspectives.insert(uniquePerspectiveName, saveState());
    // 发送透视图列表已更改的信号
    Q_EMIT perspectiveListChanged();
}
//============================================================================
// 移除一个透视图
void CDockManager::removePerspective(const QString& name)
{
    removePerspectives({name});
}
//============================================================================
// 移除多个透视图
void CDockManager::removePerspectives(const QStringList& names)
{
    int count = 0;
    for (const auto& name : names)
    {
        count += d->Perspectives.remove(name);
    }
    if (count)
    {
        // 发送透视图已移除的信号
        Q_EMIT perspectivesRemoved();
        // 发送透视图列表已更改的信号
        Q_EMIT perspectiveListChanged();
    }
}
//============================================================================
// 获取透视图名称列表
QStringList CDockManager::perspectiveNames() const
{
    return d->Perspectives.keys();
}
//============================================================================
// 打开一个透视图
void CDockManager::openPerspective(const QString& perspectiveName)
{
    // 在Perspectives中查找透视图
    const auto iterator = d->Perspectives.find(perspectiveName);
    if (d->Perspectives.end() == iterator)
    {
        return;
    }
    // 发送打开透视图的信号
    Q_EMIT openingPerspective(perspectiveName);
    // 恢复透视图状态
    restoreState(iterator.value());
    // 发送透视图已打开的信号
    Q_EMIT perspectiveOpened(perspectiveName);
}
//============================================================================
// 保存透视图到Settings中
void CDockManager::savePerspectives(QSettings& settings) const
{
settings.beginWriteArray("Perspectives", d->Perspectives.size());
int i = 0;
for (auto it = d->Perspectives.constBegin(); it != d->Perspectives.constEnd(); ++it)
{
settings.setArrayIndex(i);
settings.setValue("Name", it.key());
settings.setValue("State", it.value());
++i;
}
settings.endArray();
}
//============================================================================
// 从Settings中加载透视图
void CDockManager::loadPerspectives(QSettings& settings)
{
    d->Perspectives.clear();
    int size = settings.beginReadArray("Perspectives");
    if (!size)
    {
        settings.endArray();
        return;
    }
    for (int i = 0; i < size; ++i)
    {
        settings.setArrayIndex(i);
        QString name = settings.value("Name").toString();
        QByteArray data = settings.value("State").toByteArray();
        if (name.isEmpty() || data.isEmpty())
        {
            continue;
        }
        d->Perspectives.insert(name, data);
    }
    settings.endArray();
    // 发送透视图列表已更改的信号
    Q_EMIT perspectiveListChanged();
    // 发送透视图列表已加载的信号
    Q_EMIT perspectiveListLoaded();
}
//============================================================================
// 获取中心窗口
CDockWidget* CDockManager::centralWidget() const
{
    return d->CentralWidget;
}
//============================================================================
// 设置中心窗口
CDockAreaWidget* CDockManager::setCentralWidget(CDockWidget* widget)
{
    if (!widget)
    {
        d->CentralWidget = nullptr;
        return nullptr;
    }
    // 如果已经存在中心窗口或者已经存在其他的dock widgets，则不允许设置新的中心窗口
    if (d->CentralWidget)
    {
        qWarning("Setting a central widget not possible because there is already a central widget.");
        return nullptr;
    }
    // 如果已经存在其他的dock widgets，则不允许设置中心窗口
    if (!d->DockWidgetsMap.isEmpty())
    {
        qWarning("Setting a central widget not possible - the central widget need to be the first "
                 "dock widget that is added to the dock manager.");
        return nullptr;
    }
    // 设置dockWidget的特性
    widget->setFeature(CDockWidget::DockWidgetClosable, false);
    widget->setFeature(CDockWidget::DockWidgetMovable, false);
    widget->setFeature(CDockWidget::DockWidgetFloatable, false);
    widget->setFeature(CDockWidget::DockWidgetPinnable, false);
    d->CentralWidget = widget;
    // 将dockWidget添加到中心区域
    CDockAreaWidget* centralArea = addDockWidget(CenterDockWidgetArea, widget);
    centralArea->setDockAreaFlag(CDockAreaWidget::eDockAreaFlag::HideSingleWidgetTitleBar, true);
    return centralArea;
}
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
                                                 const QString& Group, const QIcon& GroupIcon)
{
    // 检查是否按字母顺序排序
    bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder);

    // 如果分组不为空
    if (!Group.isEmpty())
    {
        // 从ViewMenuGroups中获取分组菜单
        QMenu* GroupMenu = d->ViewMenuGroups.value(Group, 0);
        // 如果分组菜单不存在，则创建一个新的分组菜单，并添加到ViewMenu中
        if (!GroupMenu)
        {
            GroupMenu = new QMenu(Group, this);
            GroupMenu->setIcon(GroupIcon);
            d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted);
            d->ViewMenuGroups.insert(Group, GroupMenu);
        }
            // 如果分组菜单存在，但是没有设置图标，则设置图标
        else if (GroupMenu->icon().isNull() && !GroupIcon.isNull())
        {
            GroupMenu->setIcon(GroupIcon);
        }
        // 将ToggleViewAction添加到分组菜单中
        d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
        return GroupMenu->menuAction();
    }
        // 如果分组为空，则将ToggleViewAction添加到ViewMenu中
    else
    {
        d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted);
        return ToggleViewAction;
    }
}

QMenu* CDockManager::viewMenu() const
{
    return d->ViewMenu;
}

void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order)
{
    d->MenuInsertionOrder = Order;
}

bool CDockManager::isRestoringState() const
{
    return d->RestoringState;
}

int CDockManager::startDragDistance()
{
    return QApplication::startDragDistance() * 1.5;
}

CDockManager::ConfigFlags CDockManager::configFlags()
{
    return StaticConfigFlags;
}

CDockManager::AutoHideFlags CDockManager::autoHideConfigFlags()
{
    return StaticAutoHideConfigFlags;
}

void CDockManager::setConfigFlags(const ConfigFlags Flags)
{
    StaticConfigFlags = Flags;
}

void CDockManager::setAutoHideConfigFlags(const AutoHideFlags Flags)
{
    StaticAutoHideConfigFlags = Flags;
}

void CDockManager::setConfigFlag(eConfigFlag Flag, bool On)
{
    internal::setFlag(StaticConfigFlags, Flag, On);
}

void CDockManager::setAutoHideConfigFlag(eAutoHideFlag Flag, bool On)
{
    internal::setFlag(StaticAutoHideConfigFlags, Flag, On);
}

bool CDockManager::testConfigFlag(eConfigFlag Flag)
{
    return configFlags().testFlag(Flag);
}

bool CDockManager::testAutoHideConfigFlag(eAutoHideFlag Flag)
{
    return autoHideConfigFlags().testFlag(Flag);
}

CIconProvider& CDockManager::iconProvider()
{
    static CIconProvider Instance;
    return Instance;
}

void CDockManager::notifyWidgetOrAreaRelocation(QWidget* DroppedWidget)
{
    if (d->FocusController)
    {
        d->FocusController->notifyWidgetOrAreaRelocation(DroppedWidget);
    }
}

void CDockManager::notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget)
{
    if (d->FocusController)
    {
        d->FocusController->notifyFloatingWidgetDrop(FloatingWidget);
    }
}

void CDockManager::setDockWidgetFocused(CDockWidget* DockWidget)
{
    if (d->FocusController)
    {
        d->FocusController->setDockWidgetFocused(DockWidget);
    }
}

void CDockManager::hideManagerAndFloatingWidgets()
{
    hide();
    d->HiddenFloatingWidgets.clear();
    // 隐藏浮动窗口更新
    for (auto FloatingWidget : d->FloatingWidgets)
    {
        if ( FloatingWidget->isVisible() )
        {
            QList<CDockWidget*> VisibleWidgets;
            for ( auto dockWidget : FloatingWidget->dockWidgets() )
            {
                if ( dockWidget->toggleViewAction()->isChecked() )
                    VisibleWidgets.push_back( dockWidget );
            }
            // 保存为隐藏的浮动窗口，当CDockManager再次显示时将其显示出来
            d->HiddenFloatingWidgets.push_back( FloatingWidget );
            FloatingWidget->hide();
            // 隐藏浮动窗口会自动将其中的CDockWidgets标记为隐藏
            // 但是我们希望它们保持标记为可见，以便在CDockManager再次显示时恢复可见
            for ( auto dockWidget : VisibleWidgets )
            {
                dockWidget->toggleViewAction()->setChecked(true);
            }
        }
    }
}

CDockWidget* CDockManager::focusedDockWidget() const
{
    if (!d->FocusController)
    {
        return nullptr;
    }
    else
    {
        return d->FocusController->focusedDockWidget();
    }
}

QList<int> CDockManager::splitterSizes(CDockAreaWidget *ContainedArea) const
{
    if (ContainedArea)
    {
        auto Splitter = internal::findParent<CDockSplitter*>(ContainedArea);
        if (Splitter)
        {
            return Splitter->sizes();
        }
    }
    return QList<int>();
}

void CDockManager::setSplitterSizes(CDockAreaWidget *ContainedArea, const QList<int>& sizes)
{
    if (!ContainedArea)
    {
        return;
    }
    auto Splitter = internal::findParent<CDockSplitter*>(ContainedArea);
    if (Splitter && Splitter->count() == sizes.count())
    {
        Splitter->setSizes(sizes);
    }
}

CDockFocusController* CDockManager::dockFocusController() const
{
    return d->FocusController;
}

void CDockManager::setFloatingContainersTitle(const QString& Title)
{
    FloatingContainersTitle = Title;
}

QString CDockManager::floatingContainersTitle()
{
    if (FloatingContainersTitle.isEmpty())
        return qApp->applicationDisplayName();
    return FloatingContainersTitle;
}
